Flutter Engine MessageLoop
介绍
该类来自于 Google 的跨平台基础库 fml。
MessageLoop 注释:与线程关联的事件循环。
MessageLoop 整个类继承体系由多个类组成,MessageLoop 是基类,还有一系列实现类。
MessageLoop
位于 fml/message_loop.h。
Thread Local
MessageLoop 是通过 Thread Local 存储在线程中的,对应于变量:
FML_THREAD_LOCAL ThreadLocalUniquePtr<MessageLoop> tls_message_loop;
通过 Message::EnsureInitializedForCurrentThread 初始化:
void MessageLoop::EnsureInitializedForCurrentThread() {
if (tls_message_loop.get() != nullptr) {
// Already initialized.
return;
}
tls_message_loop.reset(new MessageLoop());
}
构造
MessageLoop 构造方法如下:
MessageLoop::MessageLoop()
: loop_(MessageLoopImpl::Create()),
task_runner_(fml::MakeRefCounted<fml::TaskRunner>(loop_)) {
FML_CHECK(loop_);
FML_CHECK(task_runner_);
}
构造方法中,首先创建了一个 MessageLoop 实现,同事页创建了 TaskRunner。
MessageLoopImpl
跨平台实现
根据不同平台导入不同头文件:
#if OS_MACOSX
#include "flutter/fml/platform/darwin/message_loop_darwin.h"
#elif OS_ANDROID
#include "flutter/fml/platform/android/message_loop_android.h"
#elif OS_FUCHSIA
#include "flutter/fml/platform/fuchsia/message_loop_fuchsia.h"
#elif OS_LINUX
#include "flutter/fml/platform/linux/message_loop_linux.h"
#elif OS_WIN
#include "flutter/fml/platform/win/message_loop_win.h"
#endif
Run
启动线程队列:
// message_loop.cc
void MessageLoop::Run() {
loop_->DoRun();
}
// message_loop_impl.cc
void MessageLoopImpl::DoRun() {
if (terminated_) {
// Message loops 只能启动一次
return;
}
// 该方法由平台实现来实现
Run();
// loop 可能会被停止。通过手动设置该标志实现。
terminated_ = true;
// 消息队列正在终止。检查是否由过期任务,这是过期任务的最后机会。
RunExpiredTasksNow();
// 当消息队列在终止过程中,后续任务需要从消息队列的线程中销毁
task_queue_->DisposeTasks(queue_id_);
}
// 以 Android 为例 message_loop_android
void MessageLoopAndroid::Run() {
running_ = true;
// 死循环
while (running_) {
// NDK 方法
int result = ::ALooper_pollOnce(-1, // infinite timeout
nullptr, // out fd,
nullptr, // out events,
nullptr // out data
);
if (result == ALOOPER_POLL_TIMEOUT || result == ALOOPER_POLL_ERROR) {
// This handles the case where the loop is terminated using ALooper APIs.
running_ = false;
}
}
}
在 Android 实现中,可以看到是基于 Android 的 Loop 来实现消息队列的。
问题:ALooper_pollOnce 阻塞住了,消息是在哪里处理的?
消息响应
以 Android 为例,消息响应是在构造函数中注册的:
MessageLoopAndroid::MessageLoopAndroid()
: looper_(AcquireLooperForThread()),
timer_fd_(::timerfd_create(kClockType, TFD_NONBLOCK | TFD_CLOEXEC)),
running_(false) {
FML_CHECK(looper_.is_valid());
FML_CHECK(timer_fd_.is_valid());
static const int kWakeEvents = ALOOPER_EVENT_INPUT;
ALooper_callbackFunc read_event_fd = [](int, int events, void* data) -> int {
if (events & kWakeEvents) {
reinterpret_cast<MessageLoopAndroid*>(data)->OnEventFired();
}
return 1; // continue receiving callbacks
};
int add_result = ::ALooper_addFd(looper_.get(), // looper
timer_fd_.get(), // fd
ALOOPER_POLL_CALLBACK, // ident
kWakeEvents, // events
read_event_fd, // callback
this // baton
);
FML_CHECK(add_result == 1);
}
可以看到,消息处理函数是:
void MessageLoopAndroid::OnEventFired() {
if (TimerDrain(timer_fd_.get())) {
RunExpiredTasksNow();
}
}
RunExpiredTasksNow
从具体实现回到基类,所有消息处理方法都是在 RunExpiredTasksNow 中实现的:
void MessageLoopImpl::RunExpiredTasksNow() {
FlushTasks(FlushType::kAll);
}
FlushTasks:
void MessageLoopImpl::FlushTasks(FlushType type) {
TRACE_EVENT0("fml", "MessageLoop::FlushTasks");
const auto now = fml::TimePoint::Now();
fml::closure invocation;
do {
invocation = task_queue_->GetNextTaskToRun(queue_id_, now);
if (!invocation) {
break;
}
invocation();
std::vector<fml::closure> observers =
task_queue_->GetObserversToNotify(queue_id_);
for (const auto& observer : observers) {
observer();
}
if (type == FlushType::kSingle) {
break;
}
} while (invocation);
}
其中:
- 从消息队列中取出的是闭包,取出后进行运行。
- 消息队列还有观察者,每处理一个消息都调一次观察者
- 如果模式是 kAll,会把消息队列全清掉
Flutter vs DartVM 消息队列
通过梳理,我发现 Flutter 的消息队列跟 DartVM Isolate 的消息队列不是一个东西。
- Flutter 的消息队列是一个持久运行的消息队列,在 Android 基于 Looper
- DartVM Isolate 是另一套消息队列,这套队列不是常驻的,按需运行在线程池提供的某一条线程上,用完后自动出让线程